#include <Kernel/GlobalData.h>
#include <Memory/Paging.h>
#include <IntExcept/Debug.h>
#include <Utility/CLib.h>
#include <IntExcept/Error.h>

/*
@brief 分配物理页框
@param `lpEntry` 需要改动的页目录或页表项
@return 如果分配成功，返回 `PAGE_ALLOCATE_SUCCESS`
*/
BOOL AllocateFrame(LPPageTableEntry lpEntry)
{
    // KERNEL_ASSERT(((DWORD)lpEntry >> 23) == 0x1FF, "lpEntry does not points to PTE or PDE.\r\n"); /* 高 10 位必须是 1022 或 1023，确保是页表项 */
    if (((DWORD)lpEntry >> 23) != 0x1FF)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }
    // KERNEL_ASSERT((DWORD)lpEntry % 4 == 0, "lpEntry is not 4 B aligned.\r\n"); /* 每个页表项占用双字大小，页表项起始地址一定是按双字对齐 */
    if (((DWORD)lpEntry % 4) != 0)
    {
        SetLastError(ERROR_OFFSET_ALIGNMENT_VIOLATION);
        return FALSE;
    }
    DWORD dwBitOffset = AquireAvailableBit(g_dwMemoryPoolBitmapSearchIndex, g_bmPrimitiveMemoryPool); /* 从物理内存池中分出一页物理页框 */
    if (dwBitOffset == MEMORY_BITMAP_INVALID_OFFSET)
    {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return FALSE; /* 物理内存不足 */
    }
    g_dwMemoryPoolBitmapSearchIndex = (dwBitOffset + 32) / 32; /* 更新查询索引（下次查询向前查找的 DWORD 个数） */
    DWORD_PTR dwlpFrame = (g_dwlpPrimitiveMemoryPool + dwBitOffset * 4096); /* 页框物理地址 */
    *lpEntry &= 0x00000FFF; /* 保留原有的属性位，物理地址字段清空 */
    *lpEntry |= (dwlpFrame & 0xFFFFF000 | PTE_PRESENT); /* 设置页表项，将属性置为 PRESENT */
    return TRUE;
}